
#include "list.h"

BOOL 
list_empty(list *node){
    return node->next == node && node->prev == node;
}

list_node_t *
list_node_init(list_node_t *node)
{
    node->prev = node->next = node;
    return node;
}

void 
list_add_after(list_node_t *node, list_node_t *new_node)
{
    // assert(new_node->prev == new_node->next == new_node)
    new_node->next = node->next;
    new_node->prev = node;

    node->next->prev = new_node;
    node->next = new_node;
}

void 
list_add_before(list_node_t *node, list_node_t *new_node)
{
    // assert(new_node->prev == new_node->next == new_node)
    new_node->prev = node->prev;
    new_node->next = node;

    node->prev->next = new_node;
    node->prev = new_node;
}

list *
list_append(list *list, list_node_t *new_node)
{
    list_add_before(list, new_node);
    return list;
}

list *
list_prepend(list *list, list_node_t *new_node)
{
    list_add_after(list, new_node);
    return list;
}

list_node_t *
list_remove(list_node_t *current){
    current->prev->next = current->next;
    current->next->prev = current->prev;

    current->prev = current->next = current;
    return current;
}

list_node_t *
list_pop(list *list)
{
    //if list is empty -> don't do anythin'
    if(list->next == list && list->prev == list) return NULL;
    return list_remove(list->next);
}

BOOL 
list_is_last(list *list, list_node_t *node)
{
    return list->prev == node;
}

BOOL 
list_is_first(list *list, list_node_t *node)
{
    return list->next == node;
}

BOOL 
list_len1(list *list)
{
    return !list_empty(list) && list->next == list->prev;
}

list *
list_concat(list *dest, list *src)
{
    if(list_empty(src)) return dest;

    list_node_t *last1 = dest->prev;
    list_node_t *last2 = src->prev;
    list_node_t *add = src->next;

    dest->prev = last2;
    last2->next = dest;
    last1->next = add;
    add->prev = last1;

    src->next = src->prev = src;

    return dest;
}

list_node_t *
list_first(list *list)
{
    return list_empty(list) ? NULL : list->next;
}

list_node_t *
list_last(list *list)
{
    return list_empty(list) ? NULL : list->prev;
}

